home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch21 / ffd3dtwn.c < prev    next >
C/C++ Source or Header  |  1994-08-08  |  13KB  |  629 lines

  1. #include <conio.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <graphics.h>
  5. #include <math.h>
  6. #include <alloc.h>
  7.  
  8. #define TOL 0.0005
  9. #define PI  3.14159265358979323846
  10. #define X_AXIS 1
  11. #define Y_AXIS 2
  12. #define Z_AXIS 3
  13.  
  14.  
  15. typedef struct {
  16.  float far x,y,z;
  17. } POINT3D;
  18.  
  19. typedef struct {
  20.  int x,y;
  21. } POINTint;
  22.  
  23.  
  24. /* World Limits in 2D */
  25. float WXleft;
  26. float WXright;
  27. float WYtop;
  28. float WYbottom;
  29.  
  30. /* Device Limits */
  31. int DXmin;
  32. int DYmin;
  33. int DYmax;
  34. int DXmax;
  35.  
  36. /* Rotations for 3D View in Radians*/
  37. float RX;
  38. float RY;
  39. float RZ;
  40. float COSRX;
  41. float SINRX;
  42. float COSRY;
  43. float SINRY;
  44. float COSRZ;
  45. float SINRZ;
  46.  
  47.  
  48.  
  49. void InitGraphics(void);
  50. float DegToRad(float deg);
  51. float RadToDeg(float rad);
  52. POINT3D World3DToWorld2D(POINT3D p);
  53. POINTint World2DToDevice(POINT3D p);
  54. void drawpoint(POINT3D p1);
  55. void drawline(POINT3D p1,POINT3D p2);
  56. void drawaxis(void);
  57. void SetAxesAngles(float rx, float ry, float rz);
  58. void LoadAFile(char *str);
  59. void SaveAFile(char *str);
  60. float Coordinate(int i);
  61. void InitBezierCube(void);
  62. void GetMaxima(float *xi,float *xf,
  63.            float *yi,float *yf,
  64.            float *zi,float *zf);
  65. void ScaleBezierCube(float x, float y, float z);
  66. void DrawBezierCube(void);
  67. void FreezeBezierCube(float x,float y,float z);
  68. float UVW(float vmin, float vmax, float value);
  69. float Bernstein(float t, int i);
  70. POINT3D GetBezierPoint(float u, float v, float w);
  71. void RotatePatch(int patch, int axis, float deg);
  72. void TranslatePatch(int patch, int axis, float d);
  73. void ScalePatch(int patch, int axis, float s);
  74. void GoFFD(void);
  75. void drawObjects(int n);
  76. void SetView(void);
  77.  
  78. POINT3D Cube[4][4][4];
  79. POINT3D far *Object;
  80. POINT3D far *Object2;
  81. #define MAXFACES 600      // object may have up to 2000 faces
  82.               // COMPILE USING LARGE MEMORY MODEL
  83. int PointNum;
  84. float XS,YS,ZS;
  85.  
  86.  
  87. void main()
  88. {
  89.   POINT3D p1, p2, p3;
  90.   int i, loop;
  91.   float xmin, xmax,
  92.     ymin, ymax,
  93.     zmin, zmax, t;
  94.  
  95.   if((Object = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
  96.       closegraph();
  97.       printf("ERROR: Can't allocate database!\n");
  98.       exit(1);
  99.   }
  100.  
  101.   if((Object2 = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
  102.       closegraph();
  103.       printf("ERROR: Can't allocate database!\n");
  104.       exit(1);
  105.   }
  106.  
  107.   LoadAFile("bottle.raw");
  108.   //LoadAFile("plate.raw");
  109.  
  110.   InitGraphics();
  111.   setbkcolor(WHITE);
  112.   setcolor(BROWN);
  113.   cleardevice();
  114.   /* World Limits */
  115.   WXleft   = -1.4;
  116.   WXright  =  1.4;
  117.   WYtop    =  1.4;
  118.   WYbottom = -1.4;
  119.  
  120.   InitBezierCube();
  121.   GetMaxima(&xmin,&xmax,&ymin,&ymax,&zmin,&zmax);
  122.   ScaleBezierCube(xmax, ymax, zmax);
  123.   FreezeBezierCube(xmax,ymax,zmax);
  124.  
  125.   SetView();
  126.   drawObjects(1);
  127.   //DrawBezierCube();
  128.  
  129.   InitBezierCube();
  130.   ScaleBezierCube(xmax, ymax, zmax);
  131.   // ANIMATION COMMANDS
  132.  
  133.   //USE WITH BOTTLE.RAW
  134.   RotatePatch(3, Z_AXIS, 45.0);
  135.   TranslatePatch(3, Y_AXIS, 0.5);
  136.   TranslatePatch(3, X_AXIS,-0.9);
  137.  
  138.   RotatePatch(0, Z_AXIS, -45.0);
  139.   TranslatePatch(0, Y_AXIS, -0.5);
  140.   TranslatePatch(0, X_AXIS, -0.9);
  141.  
  142.   /*
  143.   // USE WITH PLATE.RAW
  144.   RotatePatch(3, Y_AXIS, loop*9.0);
  145.   RotatePatch(2, Y_AXIS, loop*4.5);
  146.   RotatePatch(1, Y_AXIS, loop*2.0);
  147.   */
  148.   // END OF ANIMATION COMMANDS
  149.   DrawBezierCube();
  150.   GoFFD();
  151.   //SaveAFile("bottledf.raw");
  152.   for(loop=0;loop<10;loop++) {
  153.     t = loop/9.0;
  154.     // Interpolate between undeformed and deformed objects
  155.     clearviewport();
  156.     drawaxis();
  157.     setcolor(BROWN);
  158.     for(i=0;i<PointNum;i+=3) {
  159.       p1.x = Object[i].x + (Object2[i].x - Object[i].x)*t;
  160.       p1.y = Object[i].y + (Object2[i].y - Object[i].y)*t;
  161.       p1.z = Object[i].z + (Object2[i].z - Object[i].z)*t;
  162.  
  163.       p2.x = Object[i+1].x + (Object2[i+1].x - Object[i+1].x)*t;
  164.       p2.y = Object[i+1].y + (Object2[i+1].y - Object[i+1].y)*t;
  165.       p2.z = Object[i+1].z + (Object2[i+1].z - Object[i+1].z)*t;
  166.  
  167.       p3.x = Object[i+2].x + (Object2[i+2].x - Object[i+2].x)*t;
  168.       p3.y = Object[i+2].y + (Object2[i+2].y - Object[i+2].y)*t;
  169.       p3.z = Object[i+2].z + (Object2[i+2].z - Object[i+2].z)*t;
  170.  
  171.       drawline(p1,p2);
  172.       drawline(p2,p3);
  173.       drawline(p3,p1);
  174.     }
  175.   }
  176.   printf("\7");
  177.   getch();
  178.   closegraph();
  179. }
  180.  
  181. /* /////////////////////////////////////////////////////// */
  182. void SetView(void) {
  183.     int d;
  184.  
  185.     DXmin = 0.0;
  186.     DYmin = 0.0;
  187.     DYmax = getmaxy();
  188.     DXmax = getmaxy();
  189.     d = (getmaxx() - getmaxy())/2;
  190.     setviewport(d,0,getmaxy()+d,getmaxy(),1);
  191.     SetAxesAngles(20, -15, -5);
  192.     drawaxis();
  193. }
  194.  
  195.  
  196.  
  197. void drawObjects(int n) {
  198.   int i;
  199.  
  200.   setcolor(BROWN);
  201.   if (n==1)
  202.     for(i=0;i<PointNum;i+=3) {
  203.       drawline(Object[i],Object[i+1]);
  204.       drawline(Object[i+1],Object[i+2]);
  205.       drawline(Object[i+2],Object[i]);
  206.     }
  207.   else
  208.     for(i=0;i<PointNum;i+=3) {
  209.       drawline(Object2[i],Object2[i+1]);
  210.       drawline(Object2[i+1],Object2[i+2]);
  211.       drawline(Object2[i+2],Object2[i]);
  212.     }
  213. }
  214.  
  215.  
  216. void GoFFD(void) {
  217.   int i;
  218.   float Xuvw, Yuvw, Zuvw;
  219.   for(i=0;i<PointNum;i++) {
  220.     Xuvw = UVW(-XS, XS, Object[i].x);
  221.     Yuvw = UVW(-YS, YS, Object[i].y);
  222.     Zuvw = UVW(-ZS, ZS, Object[i].z);
  223.     Object2[i] = GetBezierPoint(Xuvw, Yuvw, Zuvw);
  224.   }
  225. }
  226.  
  227. void ScalePatch(int patch, int axis, float s){
  228.  int i,k;
  229.  
  230.   for(k=0;k<4;k++)
  231.    for(i=0;i<4;i++)
  232.      switch(axis) {
  233.       case X_AXIS: Cube[i][patch][k].x *= s; break;
  234.       case Y_AXIS: Cube[i][patch][k].y *= s; break;
  235.       case Z_AXIS: Cube[i][patch][k].z *= s; break;
  236.      }
  237.  
  238. }
  239.  
  240.  
  241.  
  242. void TranslatePatch(int patch, int axis, float d){
  243.  int i,k;
  244.  
  245.   for(k=0;k<4;k++)
  246.    for(i=0;i<4;i++)
  247.      switch(axis) {
  248.       case X_AXIS: Cube[i][patch][k].x += d; break;
  249.       case Y_AXIS: Cube[i][patch][k].y += d; break;
  250.       case Z_AXIS: Cube[i][patch][k].z += d; break;
  251.      }
  252.  
  253. }
  254.  
  255. void RotatePatch(int patch, int axis, float deg) {
  256.   float xc=0.0, yc=0.0, zc=0.0;
  257.   float COS, SIN;
  258.   int i,j,k;
  259.   POINT3D p, ptemp;
  260.  
  261.   deg = DegToRad(deg);
  262.   COS = cos(deg);
  263.   SIN = sin(deg);
  264.  
  265.   //find centroid of patch
  266.   for(k=0;k<4;k++)
  267.    for(i=0;i<4;i++) {
  268.       xc += Cube[i][patch][k].x;
  269.       yc += Cube[i][patch][k].y;
  270.       zc += Cube[i][patch][k].z;
  271.    }
  272.  
  273.   //divide by 16 to get center (average)
  274.    xc /= 16.0;
  275.    yc /= 16.0;
  276.    zc /= 16.0;
  277.  
  278.   // translate center of patch to origin
  279.   for(k=0;k<4;k++)
  280.    for(i=0;i<4;i++) {
  281.       Cube[i][patch][k].x -= xc;
  282.       Cube[i][patch][k].y -= yc;
  283.       Cube[i][patch][k].z -= zc;
  284.    }
  285.  
  286.   // now that center of patch is at origin, rotate about axis
  287.   for(k=0;k<4;k++)
  288.     for(i=0;i<4;i++) {
  289.       p = Cube[i][patch][k];
  290.       switch(axis) {
  291.      case X_AXIS:
  292.              ptemp.x  = p.x;
  293.              ptemp.y  = COS*p.y - SIN*p.z;
  294.              ptemp.z  = SIN*p.y + COS*p.z;
  295.              Cube[i][patch][k] = ptemp;
  296.              break;
  297.      case Y_AXIS:
  298.              ptemp.x  = COS*p.x + SIN*p.z;
  299.              ptemp.y  = p.y;
  300.              ptemp.z  = -SIN*p.x + COS*p.z;
  301.              Cube[i][patch][k] = ptemp;
  302.              break;
  303.      case Z_AXIS:
  304.              ptemp.x  = COS*p.x - SIN*p.y;
  305.              ptemp.y  = SIN*p.x + COS*p.y;
  306.              ptemp.z  = p.z;
  307.              Cube[i][patch][k] = ptemp;
  308.              break;
  309.       }
  310.     }
  311.   // translate center of patch back to original place
  312.   for(k=0;k<4;k++)
  313.    for(i=0;i<4;i++) {
  314.       Cube[i][patch][k].x += xc;
  315.       Cube[i][patch][k].y += yc;
  316.       Cube[i][patch][k].z += zc;
  317.    }
  318.  
  319. }
  320.  
  321.  
  322. float UVW(float vmin, float vmax, float value) {
  323.   return( (value - vmin)/(vmax - vmin)  );
  324. }
  325.  
  326. float Bernstein(float t, int i) {
  327.   float v;
  328.   switch(i) {
  329.     case 0: v =  pow((1.0 - t),3); break;
  330.     case 1: v =  3 * t * pow((1.0 - t),2); break;
  331.     case 2: v = 3 * pow(t,2) * (1.0 - t); break;
  332.     case 3: v = pow(t,3); break;
  333.   }
  334.   return(v);
  335. }
  336.  
  337. POINT3D GetBezierPoint(float u, float v, float w) {
  338.  int i,j,k;
  339.  POINT3D q;
  340.  float factor, wk, vk, wkvk;
  341.  
  342.  q.x = q.y = q.z = 0.0;
  343.  for(k=0;k<4;k++) {
  344.   wk = Bernstein(w,k);
  345.   for(j=0;j<4;j++) {
  346.     vk = Bernstein(v,j);
  347.     wkvk = wk * vk;
  348.     for(i=0;i<4;i++) {
  349.       factor = Bernstein(u,i) * wkvk;
  350.       q.x += Cube[i][j][k].x * factor;
  351.       q.y += Cube[i][j][k].y * factor;
  352.       q.z += Cube[i][j][k].z * factor;
  353.     }
  354.   }
  355.  }
  356.  return(q);
  357. }
  358.  
  359. void FreezeBezierCube(float x,float y,float z) {
  360.  
  361.   XS = x;
  362.   YS = y;
  363.   ZS = z;
  364. }
  365.  
  366. void GetMaxima(float *xi,float *xf,
  367.            float *yi,float *yf,
  368.            float *zi,float *zf) {
  369.   int i;
  370.   float x1=1e6,x2=-1e6,
  371.     y1=1e6,y2=-1e6,
  372.     z1=1e6,z2=-1e6;
  373.  
  374.   for(i=0;i<PointNum;i++) {
  375.  
  376.      if(Object[i].x < x1)
  377.     x1 = Object[i].x;
  378.      else
  379.     if(Object[i].x > x2)
  380.        x2 = Object[i].x;
  381.  
  382.      if(Object[i].y < y1)
  383.     y1 = Object[i].y;
  384.      else
  385.     if(Object[i].y > y2)
  386.        y2 = Object[i].y;
  387.  
  388.      if(Object[i].z < z1)
  389.     z1 = Object[i].z;
  390.      else
  391.     if(Object[i].z > z2)
  392.        z2 = Object[i].z;
  393.   }
  394.   *xi = x1;
  395.   *xf = x2;
  396.   *yi = y1;
  397.   *yf = y2;
  398.   *zi = z1;
  399.   *zf = z2;
  400. }
  401.  
  402. float Coordinate(int i) {
  403.   switch(i) {
  404.     case 0: return(-1.0);
  405.     case 1: return(-0.3);
  406.     case 2: return( 0.3);
  407.     default: return( 1.0);  //case 3
  408.   }
  409. }
  410.  
  411. void InitBezierCube(void) {
  412.  int i,j, k;
  413.  
  414.  for(k=0;k<4;k++)
  415.    for(j=0;j<4;j++)
  416.      for(i=0;i<4;i++) {
  417.        Cube[i][j][k].x = Coordinate(i);
  418.        Cube[i][j][k].y = Coordinate(j);
  419.        Cube[i][j][k].z = Coordinate(k);
  420.      }
  421. }
  422.  
  423. void ScaleBezierCube(float x, float y, float z) {
  424.  int i,j, k;
  425.  
  426.  for(k=0;k<4;k++)
  427.    for(j=0;j<4;j++)
  428.      for(i=0;i<4;i++) {
  429.        Cube[i][j][k].x *= x;
  430.        Cube[i][j][k].y *= y;
  431.        Cube[i][j][k].z *= z;
  432.      }
  433. }
  434.  
  435. void DrawBezierCube(void) {
  436.  int i,j, k;
  437.  
  438.  
  439.  setlinestyle(DOTTED_LINE,1, 1);
  440.  setcolor(RED);
  441.  
  442.  for(k=0;k<4;k++)
  443.   for(j=0;j<4;j++)
  444.     for(i=0;i<4;i++)
  445.        drawpoint(Cube[i][j][k]);
  446.  
  447.   for(j=0;j<4;j++)
  448.    for(k=0;k<4;k++)
  449.      for(i=0;i<3;i++)
  450.        drawline(Cube[i][j][k],Cube[i+1][j][k]);
  451.  
  452.   for(j=0;j<4;j++)
  453.    for(i=0;i<4;i++)
  454.      for(k=0;k<3;k++)
  455.        drawline(Cube[i][j][k],Cube[i][j][k+1]);
  456.  
  457.   for(k=0;k<4;k++)
  458.    for(i=0;i<4;i++)
  459.      for(j=0;j<3;j++)
  460.        drawline(Cube[i][j][k],Cube[i][j+1][k]);
  461.  setlinestyle(SOLID_LINE,1, 1);
  462. }
  463.  
  464. void SaveAFile(char *str)
  465. {
  466.  FILE *fptr;
  467.  int i;
  468.  if ((fptr = fopen(str,"w+t")) == NULL)
  469.     printf("\7");
  470.  else {
  471.     for(i=0;i<PointNum;i+=3)
  472.        fprintf(fptr,"%g %g %g %g %g %g %g %g %g\n",
  473.             Object2[i].x,   Object2[i].y,   Object2[i].z,
  474.             Object2[i+1].x, Object2[i+1].y, Object2[i+1].z,
  475.             Object2[i+2].x, Object2[i+2].y, Object2[i+2].z);
  476.     fclose(fptr);
  477.  }
  478. }
  479.  
  480.  
  481. void LoadAFile(char *str)
  482. {
  483.  FILE *fptr;
  484.  float x,y,z;
  485.  int bnum;
  486.  if (  (fptr = fopen(str,"r")) == NULL) {
  487.          printf("\7");
  488.  }
  489.  else {
  490.      bnum = -1;
  491.      while (!feof(fptr)) {
  492.      if ((fscanf(fptr,"%f",&x) > 0) &&
  493.          (fscanf(fptr,"%f",&y) > 0) &&
  494.          (fscanf(fptr,"%f",&z) > 0)) {
  495.           bnum++;
  496.           if(bnum < MAXFACES*3) {
  497.             Object[bnum].x = x;
  498.             Object[bnum].y = y;
  499.             Object[bnum].z = z;
  500.           }
  501.      }
  502.      }
  503.      fclose(fptr);
  504.      PointNum = bnum+1;
  505.  }
  506. }
  507.  
  508.  
  509.  
  510. void InitGraphics(void)
  511. {
  512.  int gdriver = DETECT, gmode, errorcode;
  513.  initgraph(&gdriver, &gmode, "");
  514.  if (gdriver != VGA) {
  515.   printf("VGA graphics card required.\n");
  516.   exit(1);
  517.  }
  518.  errorcode = graphresult();
  519.  if (errorcode != grOk)  /* an error occurred */
  520.  {
  521.    printf("Graphics error: %s\n", grapherrormsg(errorcode));
  522.    printf("Press any key to halt:");
  523.    getch();
  524.    exit(1); /* terminate with an error code */
  525.  }
  526.  setviewport(0,0,getmaxx(),getmaxy(),1);
  527. }
  528.  
  529. float DegToRad(float deg)
  530. {
  531.  return(deg*PI/180.0);
  532. }
  533.  
  534. float RadToDeg(float rad)
  535. {
  536.  return(rad*180.0/PI);
  537. }
  538.  
  539. void SetAxesAngles(float rx, float ry, float rz) {
  540.     RX = DegToRad(rx);
  541.     RY = DegToRad(ry);
  542.     RZ = DegToRad(rz);
  543.     COSRX = cos(RX);
  544.     SINRX = sin(RX);
  545.     COSRY = cos(RY);
  546.     SINRY = sin(RY);
  547.     COSRZ = cos(RZ);
  548.     SINRZ = sin(RZ);
  549. }
  550.  
  551.  
  552.  
  553. POINT3D World3DToWorld2D(POINT3D p)
  554. {
  555.   POINT3D ptemp;
  556.   ptemp = p;
  557.   if (RX) {
  558.     ptemp.x  = p.x;
  559.     ptemp.y  = COSRX*p.y - SINRX*p.z;
  560.     ptemp.z  = SINRX*p.y + COSRX*p.z;
  561.     p = ptemp;
  562.   }
  563.   if (RY) {
  564.     ptemp.x  = COSRY*p.x + SINRY*p.z;
  565.     ptemp.y  = p.y;
  566.     ptemp.z  = -SINRY*p.x + COSRY*p.z;
  567.     p = ptemp;
  568.   }
  569.   if (RZ) {
  570.     ptemp.x  = COSRZ*p.x - SINRZ*p.y;
  571.     ptemp.y  = SINRZ*p.x + COSRZ*p.y;
  572.     ptemp.z  = p.z;
  573.   }
  574.   if (fabs(ptemp.x) < TOL)  ptemp.x = 0.0;
  575.   if (fabs(ptemp.y) < TOL)  ptemp.y = 0.0;
  576.   if (fabs(ptemp.z) < TOL)  ptemp.z = 0.0;
  577.   return(ptemp);
  578. }
  579.  
  580. POINTint World2DToDevice(POINT3D p)
  581. {
  582.  
  583.  POINTint ptemp;
  584.  ptemp.x = (WXleft-p.x)*(DXmax-DXmin)/(WXleft-WXright) + DXmin + 0.5;
  585.  ptemp.y = (WYtop-p.y)*(DYmax-DYmin)/(WYtop-WYbottom) + DYmin + 0.5;
  586.  return(ptemp);
  587.  
  588. }
  589.  
  590. void drawpoint(POINT3D p1)
  591. {
  592.  /* draws a 3D point   */
  593.  POINTint p2;
  594.  p1.z = -p1.z;
  595.  p2 = World2DToDevice(World3DToWorld2D(p1));
  596.  rectangle(p2.x - 2, p2.y - 2, p2.x + 2, p2.y + 2);
  597. }
  598.  
  599. void drawline(POINT3D p1,POINT3D p2)
  600. {
  601.  /* draws a 3D line  */
  602.   POINTint p11,p22;
  603.   p1.z = -p1.z;
  604.   p2.z = -p2.z;
  605.   p11  = World2DToDevice(World3DToWorld2D(p1));
  606.   p22  = World2DToDevice(World3DToWorld2D(p2));
  607.   line(p11.x,p11.y,p22.x,p22.y);
  608. }
  609.  
  610. void drawaxis(void) {
  611.   POINT3D p1,p2;
  612.  
  613.   p1.x = p1.y = p1.z = 0;
  614.  
  615.   p2.x = 1; p2.y = 0; p2.z=0;
  616.   setcolor(RED);
  617.   drawline(p1,p2);
  618.  
  619.   p2.x = 0; p2.y = 1; p2.z=0;
  620.   setcolor(GREEN);
  621.   drawline(p1,p2);
  622.  
  623.   p2.x = 0; p2.y = 0; p2.z=1;
  624.   setcolor(BLUE);
  625.   drawline(p1,p2);
  626.  
  627.   setcolor(WHITE);
  628. }
  629.